#pragma once

// SAPI includes
#include <sapi.h>           
#include <sphelper.h>
#include <spuihelp.h>

// HX includes
#include "HXPlayer.h"
#include "HXDisplay.h"
#include "HXViseme.h"
#include "HXTTSEngine.h"
#include "HXTTSEngineSAPI.h"
#include "HXTTSEngineMary.h"

using namespace std;

//-----------------------------------------------------------------------------

class HXSpeech
{
private:


public:
	HXSpeech(void);
	HXSpeech(int fps, int mixFrames, float mixFactor, double visemeModulator, double rate);
	~HXSpeech(void);

	void Lock() { m_speaking = true; EnterCriticalSection(&m_criticalSection_Speech); }
    void Unlock() { LeaveCriticalSection(&m_criticalSection_Speech); m_speaking = false; }
	bool IsLocked() { return m_speaking; }

	int SetEngine(HXTTSEngineID id);

	void GetVoices(vector<string>& voices) { m_engine->GetVoices(voices); }
	void SetVoice(string voice) { m_engine->SetVoice(voice); }
	void SetEnginekHz(int kHz) { m_engine->SetEnginekHz(kHz); }

	void SetVisemeModulator(double visemeModulator) { m_visemeModulator = visemeModulator; m_engine->SetVisemeModulator(visemeModulator);}
	double GetVisemeModulator(void) { return m_visemeModulator; }

	void SetAVSyncAdjust(double avSyncAdjust) { m_avSyncAdjust = avSyncAdjust; m_engine->SetAVSyncAdjust(avSyncAdjust);}
	double GetAVSyncAdjust(void) { return m_avSyncAdjust; }

	void SetFPS(int fps) { m_fps = fps; m_engine->SetFPS(fps); }
	int GetFPS(void) { return m_fps; }

	void SetMix(int mixFrames, float mixFactor) { m_mixFrames = mixFrames; m_mixFactor = mixFactor; }
	int GetMixFrames() { return m_mixFrames; }
	float GetMixFactor() { return m_mixFactor; }

	void SetRate(double rate) { m_rate = rate; m_engine->SetRate(rate); }
	double GetRate(void) { return m_rate; }

	void SetRampFunc(HXBlendMode mode) { m_engine->SetRampFunc(mode); }
	HXBlendMode GetRampFunc() { return m_engine->GetRampFunc(); }

	void SetOverlap(double overlap) { m_overlap = overlap; m_engine->SetOverlap(overlap); }

	void SetVisemeMap(map<wstring,vector<vector<HXVisemeBlendShape>>>& visemeMap) { m_visemeMap = visemeMap; m_engine->SetVisemeMap(visemeMap); };

	HRESULT Speak(const wstring& text);
	HRESULT Speak(const wstring& text, bool* doEarlyExit) { m_pbEarlyExit = doEarlyExit; HRESULT hr = Speak(text); m_pbEarlyExit = NULL; return hr; }

	void RenderVisemeMix(vector<vector<HXViseme>>& frames, size_t frame_position, size_t mix_size, float mix_factor, float ampl_factor = 1.0f);

	void SetDisplay(HXDisplay* pDisp) { Lock(); m_pDisp = pDisp; Unlock(); }


private:
	bool                m_speaking;
	HXDisplay*          m_pDisp;
	
	int					m_mixFrames;
	float				m_mixFactor;

	// engine values for changing the engine
	int                 m_fps;
	double              m_visemeModulator;
	double              m_rate;
	double              m_avSyncAdjust;
	double              m_overlap;
	HXBlendMode			m_rampFunc;
	map<wstring,vector<vector<HXVisemeBlendShape>>> m_visemeMap;

	HXTTSEngine*		m_engine;
	bool*				m_pbEarlyExit;

    int playMMIO(string& audio, HWAVEOUT &hWaveOut, WAVEHDR &waveHdr, double* factor, HPSTR &lpData);
	int WriteFramesToFile(vector<vector<HXViseme>>& frames);

	CRITICAL_SECTION	m_criticalSection_Speech;

	//ofstream m_mixout;
};

//=============================================================================

extern HXSpeech g_speechtts;
